using System;
using System.Text.RegularExpressions;
using HtmlAgilityPack;

namespace GearUp.Crawler
{
    public class LinkManager
    {
        private readonly string baseUrl;
        private readonly string domainUrl;

        public LinkManager(string baseUrl)
        {
            this.baseUrl = baseUrl.TrimEnd('/');
            domainUrl = LinkDomain(baseUrl);
        }

        public string FullyQualifyLink(string originatingUrl, string linkUrl)
        {
            var fullyQualifiedLink = linkUrl;
            var linkDomain = LinkDomain(linkUrl);

            if (!string.IsNullOrEmpty(linkDomain) && linkDomain != domainUrl)
                return string.Empty;

            if (linkUrl.Contains("../"))
            {
                fullyQualifiedLink = ResolveRelativePath(originatingUrl, linkUrl);
            }
            else if (!linkUrl.StartsWith(domainUrl))
            {
                if (linkUrl.StartsWith("/"))
                    fullyQualifiedLink = domainUrl + linkUrl;
                else if (linkUrl.StartsWith("#"))
                    fullyQualifiedLink = originatingUrl + linkUrl;
                else
                    fullyQualifiedLink = originatingUrl.Substring(0, originatingUrl.LastIndexOf("/") + 1) + linkUrl;
            }

            if (!fullyQualifiedLink.StartsWith(baseUrl))
                fullyQualifiedLink = string.Empty;

            return fullyQualifiedLink;
        }

        private static string ResolveRelativePath(string originatingUrl, string relativeUrl)
        {
            var resolvedUrl = String.Empty;

            var relativeUrlArray = relativeUrl.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
            var originatingUrlElements = originatingUrl.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
            var indexOfFirstNonRelativePathElement = 0;
            for (var i = 0; i <= relativeUrlArray.Length - 1; i++)
            {
                if (relativeUrlArray[i] == "..") continue;
                indexOfFirstNonRelativePathElement = i;
                break;
            }

            var countOfOriginatingUrlElementsToUse = originatingUrlElements.Length - indexOfFirstNonRelativePathElement - 1;
            for (var i = 0; i <= countOfOriginatingUrlElementsToUse - 1; i++)
            {
                if (originatingUrlElements[i] == "http:" || originatingUrlElements[i] == "https:")
                    resolvedUrl += originatingUrlElements[i] + "//";
                else
                    resolvedUrl += originatingUrlElements[i] + "/";
            }

            for (var i = 0; i <= relativeUrlArray.Length - 1; i++)
            {
                if (i < indexOfFirstNonRelativePathElement) continue;
                resolvedUrl += relativeUrlArray[i];

                if (i < relativeUrlArray.Length - 1)
                    resolvedUrl += "/";
            }

            return resolvedUrl;
        }

        internal static string LinkDomain(string linkUrl)
        {
            if (string.IsNullOrEmpty(linkUrl))
                return linkUrl;

            var match = Regex.Match(linkUrl, @"^http[s]?[:/]+[^/]+");
            return match.Success ? match.Captures[0].Value : string.Empty;
        }

        public static string ExtractUrlFromNode(HtmlNode node)
        {
            if (node == null || node.NodeType != HtmlNodeType.Element || node.Name != "a")
            {
                return string.Empty;
            }
            return node.Attributes["href"] == null ? string.Empty : node.Attributes["href"].Value;
        }
    }
}